/**
 * Copyright (C) 2011 Vinicius Vielmo Cogo, Marcelo Pasin, and the authors
 * indicated in the @author tags.
 * 
 * This file is part of DiversityAgent.
 * 
 * DiversityAgent is a free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * DiversityAgent is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with DiversityAgent. If not, see <http://www.gnu.org/licenses/>.
 */
package diversities;

import java.util.ArrayList;
import java.util.Properties;

import diversity_agent.DataContainer;
import diversity_agent.Image;
import diversity_agent.VirtualMachine;

/**
 * 
 * @author Vinicius Vielmo Cogo (vielmo at lasige.di.fc.ul.pt)
 * @version 0.1-beta
 * @since 2011-11-18
 * 
 */
public class OperatingSystem extends diversity_agent.Diversity
{

	private DataContainer	mDataContainer;

	public OperatingSystem()
	{
		mDiversityAxis = diversity_agent.DIVERSITY_AXIS.SUPPORT_SOFTWARE;
		mDependencies.add("cloud.name");
		this.mDataContainer = null;
	}

	@Override
	public Properties getContribution(Properties theProperties,
			DataContainer theDataContainer)
	{
		this.mDataContainer = theDataContainer;

		if (theProperties.getProperty("cloud.name") != null) {
			theProperties = setOsNeverUsedOnCloud(theProperties);

			if (theProperties.getProperty("disk.image.name") == null) {
				theProperties = setAnyImageOnCloud(theProperties);
			}
		}

		if (theProperties.getProperty("disk.image.name") == null) {
			theProperties = setOsNeverUsed(theProperties);
		}

		if (theProperties.getProperty("disk.image.name") == null) {
			theProperties = setOsNeverUsedOnSomeCloud(theProperties);
		}

		if (theProperties.getProperty("disk.image.name") == null) {
			theProperties = setOsNeverUsedOnHost(theProperties);
		}

		if (theProperties.getProperty("disk.image.name") == null) {
			theProperties = setAnyImage(theProperties);
		}

		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setOsNeverUsed(Properties theProperties)
	{
		int aCounter;
		for (Image aImage : mDataContainer.retrieveImages()) {
			aCounter = 0;
			for (VirtualMachine aVm : mDataContainer.retrieveVms()) {
				Image aImageVm = mDataContainer.retrieveImage(aVm
						.getImageName());
				if (aImage.getOsName().equals(aImageVm.getOsName())) {
					aCounter++;
				}
			}
			if (aCounter == 0) {
				theProperties.setProperty("disk.image.name", aImage.getName());
				return theProperties;
			}
		}
		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setOsNeverUsedOnSomeCloud(Properties theProperties)
	{
		int aCounter;
		for (Image aImage : mDataContainer.retrieveImages()) {
			for (diversity_agent.Cloud aCloud : mDataContainer.retrieveClouds()) {
				aCounter = 0;
				for (VirtualMachine aVm : mDataContainer.retrieveVms()) {
					if (aCloud.getCloudName().equals(aVm.getCloudName())) {
						Image aImageVm = mDataContainer.retrieveImage(aVm
								.getImageName());
						if (aImage.getOsName().equals(aImageVm.getOsName())) {
							aCounter++;
						}
					}
				}
				if (aCounter == 0) {
					theProperties.setProperty("cloud.name", aCloud
							.getCloudName());
					theProperties.setProperty("disk.image.name", aImage
							.getName());
					return theProperties;
				}
			}
		}
		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setOsNeverUsedOnCloud(Properties theProperties)
	{
		String aCloudName = theProperties.getProperty("cloud.name");
		int aCounter;
		for (Image aImage : mDataContainer.retrieveImages()) {
			aCounter = 0;
			for (VirtualMachine aVm : mDataContainer.retrieveVms()) {
				if (aCloudName.equals(aVm.getCloudName())) {
					Image aImageVm = mDataContainer.retrieveImage(aVm
							.getImageName());
					if (aImage.getOsName().equals(aImageVm.getOsName())) {
						aCounter++;
					}
				}
			}
			if (aCounter == 0) {
				theProperties.setProperty("disk.image.name", aImage.getName());
				return theProperties;
			}
		}
		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setOsNeverUsedOnHost(Properties theProperties)
	{
		int aCounter;
		for (Image aImage : mDataContainer.retrieveImages()) {
			for (VirtualMachine aVm : mDataContainer.retrieveVms()) {
				String aCloudName = aVm.getCloudName();
				String aHostName = aVm.getHostName();
				aCounter = 0;
				for (VirtualMachine aVmInside : mDataContainer.retrieveVms()) {
					if (aHostName.equals(aVmInside.getHostName())) {
						Image aImageVm = mDataContainer.retrieveImage(aVmInside
								.getImageName());
						if (aImage.getOsName().equals(aImageVm.getOsName())) {
							aCounter++;
						}
					}
				}
				if (aCounter == 0) {
					theProperties.setProperty("cloud.name", aCloudName);
					theProperties.setProperty("host.name.equal", aHostName);
					theProperties.setProperty("disk.image.name", aImage
							.getName());
					return theProperties;
				}
			}
		}
		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setAnyImage(Properties theProperties)
	{
		ArrayList<Image> aImages = mDataContainer.retrieveImages();
		if (aImages != null) {
			theProperties.setProperty("disk.image.name", (aImages.get(Math
					.round((float) Math.random() * (aImages.size() - 1))))
					.getName());
		}
		return theProperties;
	}

	/**
	 * 
	 * @param theProperties
	 * @return
	 */
	private Properties setAnyImageOnCloud(Properties theProperties)
	{
		String aCloud = theProperties.getProperty("cloud.name");
		ArrayList<Image> aImages = mDataContainer.retrieveImages();
		int aRandom = 0;
		if (aImages != null) {
			do {
				aRandom = Math.round((float) Math.random()
						* (aImages.size() - 1));
			} while (!aImages.get(aRandom).getAllocatedClouds()
					.contains(aCloud));
			theProperties.setProperty("disk.image.name", (aImages.get(aRandom))
					.getName());
		}
		return theProperties;
	}
}
